'''
Created on Nov 3, 2009

@author: wangjo
'''
from google.appengine.ext import db
from google.appengine.ext.db import polymodel
import logging

DEFAULT_OFFSET = 50
PER_CRAWLER_COUNT = 5
class model(polymodel.PolyModel):
    username = db.StringProperty(required = True)
    homepage = db.LinkProperty(required = True)
    name = db.StringProperty()
    status = db.StringProperty()
    gender = db.BooleanProperty() #true as male, false 
    category = db.StringListProperty()  #like actor, model, hostness etc
    birthdate = db.StringProperty()
    count_album_total = db.IntegerProperty()
    astrology = db.StringProperty()
    address = db.StringProperty()
    age = db.StringProperty()
    visitcount = db.IntegerProperty()
    avatar = db.LinkProperty()
    created = db.DateTimeProperty(auto_now_add=True)
    updated = db.DateTimeProperty(auto_now=True) 
    
    @staticmethod
    def add_model(username, url):
        if not username: return
        username = username.strip()
        m = db.Query(model).filter('username =', username).get()
        if m: return
        m = model(username = username, homepage=db.Link(url))
        m.put()
        
    @staticmethod
    def get_models(limit, offset):
        if not limit:
            limit = DEFAULT_OFFSET
        if not offset:
            offset = 0
        return db.Query(model).order('username').fetch(limit, offset)
    
    @staticmethod
    def get_model_count():
        limit = 1000
        result = 0
        q = db.Query(model)
        count = q.count(limit)
        while count == limit and result <1:
            result += count
            q = db.Query(model).fetch(limit, result)
            count = len(q)
        result += count
        return result
    
    @staticmethod
    def get_model(username):
        if not username: return None
        return db.Query(model).filter('username =', username).get()
    
    def get_photo_count(self):
        return db.Query(photo).filter('model =', self).count()
    
    def get_photos(self):
        return db.Query(photo).filter('model =', self).fetch(1000)
    
    def get_album_count(self):
        return db.Query(album).filter('model =', self).count()
    
    def get_albums(self):
        return db.Query(album).filter('model =', self).fetch(1000)

class topgirl(model):
    topgirl = db.BooleanProperty()
    score = db.IntegerProperty()
    friends = db.StringListProperty()
    
    @staticmethod
    def add_topgirl(username, model):
        if not username: return
        username = username.strip()
        t = db.Query(topgirl).filter('username =', username).get()
        if not t:
            t = topgirl(username = username, homepage = model.homepage, topgirl=True)
        t.name = model.name
        t.category = model.category
        t.gender = False
        t.birthdate = model.birthdate
        t.astrology = model.astrology
        t.avatar = model.avatar
        t.address = model.address
        t.age = model.age
        t.visitcount = model.visitcount
        t.put()
        return t
    
    @staticmethod 
    def get_topgirls(limit, offset):
        if not limit:
            limit = DEFAULT_OFFSET
        if not offset:
            offset = 0
        return db.Query(topgirl).filter('gender =', False).order('username').fetch(limit, offset)
    
    @staticmethod
    def get_topgirl_count():
        limit = 1000
        result = 0
        q = db.Query(model).filter('gender =', False)
        count = q.count(limit)
        while count == limit and result <1:
            result += count
            q = db.Query(topgirl).filter('gender =', False).fetch(limit, result)
            count = len(q)
        result += count
        return result
    
class cronlog(polymodel.PolyModel):
    action = db.StringProperty()
    content = db.StringProperty()
    target = db.StringProperty()
    successed = db.BooleanProperty()
    created = db.DateTimeProperty(auto_now_add=True)
    updated = db.DateTimeProperty(auto_now=True) 
    
    @staticmethod
    def get_non_crawled_models(count):
        if not count:
            count = PER_CRAWLER_COUNT
        q = db.Query(cronlog).filter('target =', 'model').filter('successed =', True).order('-created')
        m = q.get()
        if m:
            s = db.Query(model).filter('username =', m.content).get()
            return db.Query(model).filter('created >', s.created).order('created').fetch(count)
        else:
            return db.Query(model).order('created').fetch(count)
    
    @staticmethod    
    def get_non_crawled_avatars(count):
        if not count:
            count = PER_CRAWLER_COUNT
        q = db.Query(cronlog).filter('target =', 'avatar').filter('successed =', True).order('-created')
        m = q.get()
        if m:
            s = db.Query(model).filter('username =', m.content).get()
            return db.Query(model).filter('created >', s.created).order('created').fetch(count)
        else:
            return db.Query(model).order('created').fetch(count)
    
    @staticmethod  
    def get_non_crawled_photos(count):
        if not count:
            count = PER_CRAWLER_COUNT
        q = db.Query(cronlog).filter('target =', 'photo').filter('successed =', True).order('-created')
        m = q.get()
        if m:
            s = db.Query(photo).filter('url =', m.content).get()
            return db.Query(photo).filter('created >', s.created).order('created').fetch(count)
        else:
            return db.Query(photo).order('created').fetch(count)
    
    @staticmethod  
    def get_non_crawled_albums(count):
        if not count:
            count = PER_CRAWLER_COUNT
        q = db.Query(cronlog).filter('target =', 'album').filter('successed =', True).order('-created')
        a = q.get()
        if a:
            s = db.Query(album).filter('url =', a.content).get()
            return db.Query(album).filter('created >', s.created).order('created').fetch(count)
        else:
            return db.Query(album).order('created').fetch(count)
        
    @staticmethod  
    def get_non_downloaded_photos(limit, offset):
        if not limit:
            limit = PER_CRAWLER_COUNT
        q = db.Query(cronlog).filter('target =', 'photo').filter('action =', 'download').filter('successed =', True).order('-created')
        a = q.get()
        if a:
            s = db.Query(photo).filter('url =', a.content).get()
            return db.Query(photo).filter('created >', s.created).order('created').fetch(limit, offset)
        else:
            return db.Query(photo).order('created').fetch(limit, offset)
    
    @staticmethod  
    def get_non_downloaded_avatars(limit, offset):
        if not limit:
            limit = PER_CRAWLER_COUNT
        q = db.Query(cronlog).filter('target =', 'avatar').filter('action =', 'download').filter('successed =', True).order('-created')
        a = q.get()
        if a:
            s = db.Query(model).filter('username =', a.content).get()
            return db.Query(model).filter('gender =', False).filter('created >', s.created).order('created').fetch(limit, offset)
        else:
            return db.Query(model).filter('avatar !=', None).order('avatar').order('created').fetch(limit, offset)
    
    @staticmethod  
    def get_non_crawled_gallery(count):
        if not count:
            count = PER_CRAWLER_COUNT
        q = db.Query(cronlog).filter('target =', 'gallery').filter('successed =', True).order('-created')
        m = q.get()
        if m:
            s = db.Query(model).filter('username =', m.content).get()
            return db.Query(model).filter('gender =', False).filter('created >', s.created).order('created').fetch(count)
        else:
            return db.Query(model).filter('gender =', False).order('created').fetch(count)
        
    @staticmethod
    def add_crawler_model(username, successed):
        l = cronlog(action='crawler', content =username, target='model', successed=successed)
        l.put()
        
    @staticmethod
    def add_crawler_avatar(username, successed):
        l = cronlog(action='crawler', content =username, target='avatar', successed=successed)
        l.put()
    
    @staticmethod
    def add_crawler_gallery(username, successed):
        l = cronlog(action='crawler', content =username, target='gallery', successed=successed)
        l.put()
        
    @staticmethod
    def add_crawler_photo(url, successed):
        l = cronlog(action='crawler', content =url, target='photo', successed=successed)
        l.put()
        
    @staticmethod
    def add_download_photo(imagekey, successed):
        p = photo.get(imagekey)
        if p:
            logging.debug('photo url:%s'%p.url)
            l = cronlog(action='download', content =p.url, target='photo', successed=successed)
            l.put()
            return p
        else:
            logging.debug('add download photo log has error with key: %s'%imagekey)
            return None
    
    @staticmethod
    def add_download_avatar(username, successed):
        l = cronlog(action='download', content= username, target='avatar', successed=successed)
        l.put()
    
    @staticmethod
    def add_crawler_album(url, successed):
        l = cronlog(action='crawler', content =url, target='album', successed=successed)
        l.put()
    
class album(db.Model):
    model = db.ReferenceProperty(model, required = True)
    title = db.StringProperty()
    url = db.LinkProperty(required = True)
    count_photo = db.IntegerProperty()
    count_visit = db.IntegerProperty()
    count_comment = db.IntegerProperty() 
    albumdate = db.StringProperty()
    mtpalbum = db.BooleanProperty(default = False)
    selected = db.BooleanProperty(default = False)
    cover = db.LinkProperty()
    created = db.DateTimeProperty(auto_now_add=True)
    updated = db.DateTimeProperty(auto_now=True) 
    
    def get_photos(self):
        return db.Query(photo).filter('album =', self).fetch()
    
    def get_photo_count(self):
        return db.Query(photo).filter('album =', self).count()
    
    @staticmethod
    def add_album(model, url, title, count_photo, count_visit, count_comment, albumdate, cover):
        if not model: return
        if not url: return 
        q = db.Query(album).filter('model =', model).filter('url =', url)
        m = q.get()
        if not m:
            m = album(model = model, url = db.Link(url))
        m.title = title
        m.count_photo = int(count_photo)
        m.count_visit = int(count_visit)
        m.count_comment = int(count_comment)
        m.albumdate = albumdate
        m.cover = db.Link(cover)
        m.put()
        return m

    @staticmethod 
    def get_albums(limit, offset):
        if not limit:
            limit = DEFAULT_OFFSET
        if not offset:
            offset = 0
        return db.Query(album).order('created').fetch(limit, offset)
    
    @staticmethod
    def get_album_count():
        limit = 1000
        result = 0
        q = db.Query(album)
        count = q.count(limit)
        while count == limit and result <1:
            result += count
            q = db.Query(topgirl).fetch(limit, result)
            count = len(q)
        result += count
        return result
   
class rawphotodata(db.Model):
    rawdata = db.BlobProperty()
    url = db.LinkProperty()
    ptype = db.StringProperty()
    model = db.ReferenceProperty(model)
    when = db.DateTimeProperty(auto_now_add=True)
    lastupdated = db.DateTimeProperty(auto_now=True)
    
    @staticmethod
    def get_rawphoto(url, model=None):
        if not url: return None
        q = db.Query(rawphotodata)
        if model:
            q.filter('model =', model)
        return q.filter('url =', url).get()
            
    @staticmethod
    def add_avatar_photo(url, blob, model):
        if not url: return None
        if not blob: return None
        if not model: return None
        p = db.Query(rawphotodata).filter('model = ', model).filter('url =', url).get()
        if not p:
            p = rawphotodata(rawdata = blob, url = url, ptype='avatar', model = model)
        else:
            p.ptype = 'avatar'
            p.rawdata = blob
        
        p.put()
        return p
        
    @staticmethod
    def add_model_photo(url, blob, model):
        if not url: return None
        if not blob: return None
        if not model: return None
        p = db.Query(rawphotodata).filter('model = ', model).filter('url =', url).get()
        if not p:
            p = rawphotodata(rawdata = blob, url = url, ptype='model', model = model)
        else:
            p.ptype = 'model'
            p.rawdata = blob
        
        p.put()  
        return p
    
    @staticmethod
    def add_common_photo(url, blob, model = None):
        if not url: return None
        if not blob: return None
        q = db.Query(rawphotodata)
        if model:
            q.filter('model =', model)
        p = q.filter('url =', url).get()
        if not p:
            p = rawphotodata(rawdata = blob, url = url)
        else:
            p.rawdata = blob
        if model:
            p.model = model
            p.ptype = 'model'
        else:
            p.ptype = 'common'
        
        p.put()  
        return p  
    
class photo(db.Model):
    title = db.StringProperty()
    url = db.LinkProperty(required = True)
    width = db.IntegerProperty()
    height = db.IntegerProperty()
    album = db.ReferenceProperty(album)
    model = db.ReferenceProperty(model)
    comment = db.TextProperty()
    created = db.DateTimeProperty(auto_now_add=True)
    updated = db.DateTimeProperty(auto_now=True) 
    
    @staticmethod
    def add_photo(url, model, album = None, title = None, comment = None):
        if not url: return
        if not model: return
        p = db.Query(photo).filter('model =', model).filter('url =', url).get()
        if not p:
            p = photo(title = title, url = url, album = album, model = model, comment = comment)
            p.put()
        return p
        